package main

import (
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strconv"
)

type TestChaincode struct {
}

func (t *TestChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("初始化链码 TestChaincode")

	err := stub.PutState("sirui", []byte("100000"))
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

func (t *TestChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("..................Invoke...................")
	function, args := stub.GetFunctionAndParameters()
	if function == "add" {
		return t.add(stub, args)
	} else if function == "delete" {
		return t.delete(stub, args)
	} else if function == "query" {
		return t.query(stub, args)
	} else if function == "transfer" {
		return t.transfer(stub, args)
	}
	return shim.Error(`支持事件： "invoke" "delete" "query" "transfer" `)
}

func (t *TestChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) < 3 {
		return shim.Error("输入参数数量不正确！")
	}
	aVal, err := stub.GetState(args[0])
	if err != nil {
		return shim.Error(args[0] + "输入账户信息不存在！")
	}
	v, err := strconv.Atoi(string(aVal))
	if err != nil {
		return shim.Error(args[0] + "账户金额异常")
	}
	if v <= 0 {
		return shim.Error(args[0] + "账户余额不足！")
	}
	bVal, err := stub.GetState(args[1])
	if err != nil {
		return shim.Error(args[1] + "输入账户信息不存在！")
	}
	vb, err := strconv.Atoi(string(bVal))
	if err != nil {
		return shim.Error(args[0] + "账户金额异常")
	}
	amt, err := strconv.Atoi(string(args[2]))
	if err != nil {
		return shim.Error("转账金额不正确[" + args[2] + "]")
	}
	if v-amt < 0 {
		shim.Error("账户余额不足，账号[" + args[0] + "]")
	}
	stub.PutState(args[0], []byte(strconv.Itoa(v-amt)))
	stub.PutState(args[1], []byte(strconv.Itoa(vb+amt)))
	return shim.Success(nil)
}

func (t *TestChaincode) add(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	fmt.Println("增加账户")
	var err error
	if len(args) == 1 {
		err = stub.PutState(args[0], []byte("0"))
	} else if len(args) == 2 {
		_, err = strconv.Atoi(args[1])
		if err != nil {
			return shim.Error("输入参数初始金额不正确！")
		}
		err = stub.PutState(args[0], []byte(args[1]))
	} else {
		return shim.Error("输入参数个数不正确！")
	}
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

func (t *TestChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("输入参数个数不正确！")
	}
	acc := args[0]
	err := stub.DelState(acc)
	if err != nil {
		return shim.Error("删除账户失败," + err.Error())
	}
	return shim.Success(nil)
}

func (t *TestChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("输入参数个数不正确!")
	}
	acc := args[0]
	val, err := stub.GetState(acc)
	if err != nil {
		return shim.Error("查询账户信息失败," + err.Error())
	}

	return shim.Success(val)
}

func main() {
	err := shim.Start(new(TestChaincode))
	if err != nil {
		fmt.Printf("启动链码TestChaincode失败: %s", err)
	}
}
